#include "MsgQueueManage.h"
#include "MediaUdpClient.h"
#include "CurtainActManager.h"
#include <log.h>
#include "MediaUdpServer.h"
#include "MediaTcpClient.h"

namespace Media{

std::map<uint16_t, MsgQueueManage *>  MsgQueueManage::sm_objectMap;

std::recursive_mutex 	              MsgQueueManage::sm_mapMutex;


bool MsgQueueManage::getShureCommandCnt(const unsigned char *data,int len,int *iCmdCnt)
{
    /*命令分割*/
    int comand_argc = 0;
    for(int index = 0;index < len && (index+1) < COMMAND_MAX_LEN; index++)
    {
        if(data[index] != ' ' && data[index+1] == ' ')
        {
            comand_argc++;
        }
    }
    if(data[len -1] != ' ')
        comand_argc++;

    if(comand_argc == 0)
    {
        printf("comand_argc error");
        return false;
    }

    *iCmdCnt = comand_argc;

    return true;
}

bool MsgQueueManage::shureCommandPrase(MessagePtr& msgPtr,const unsigned char *data, int len )
{       
    bool iRet = true;
    unsigned char comand_argc;
    unsigned char ** comand_argv = NULL;
    unsigned short comand_len = 0;
    unsigned char comand_index = 0;
    unsigned char spilt_start = 0;
    unsigned short new_command_pos =0;

    unsigned short index = 0;
    unsigned short found_index = 0;

    int iCmdCnt = 0;
    if(!getShureCommandCnt(data,len,&iCmdCnt))
    {
        printf("errormsg [%s][%d] [%s]\n",__FILE__,__LINE__,__FUNCTION__); 
        return false;
    }

    //printf("data:%s len:%d,iCmdCnt:%d\n",data,len,iCmdCnt);

    /*分配 comand_argc个 unsigned char *指针*/
    comand_argc = iCmdCnt;
    //printf("cmd argc:%d",comand_argc);
    comand_argv = malloc(comand_argc * sizeof(unsigned char *));
    if(comand_argv == NULL)
    {
        iRet = false;
        goto end;
    }

    memset(comand_argv,0,comand_argc * sizeof(unsigned char *));

    spilt_start = 1;
    comand_index = 0;
    for(index=0;index<len;index++)
    {
        if(data[index] != ' ')
        {
            if(spilt_start) 
            {
                spilt_start = 0;
                comand_len = 0;
                new_command_pos = index;
            }
            comand_len++;
        }
        else
        {
            spilt_start = 1;
        }

        if(data[index] != ' ' && (data[index+1] == ' ' || index == len -1))
        {
            comand_argv[comand_index] = malloc(comand_len + 1);
            if(comand_argv[comand_index] == NULL)
            {
                goto end;
            }

            memset(comand_argv[comand_index],0,comand_len + 1);
            memcpy(comand_argv[comand_index],&data[new_command_pos],comand_len);
            comand_index++;
        }
    }

    /* to do */
#if 0
    for(index=0;index<comand_argc;index++)
    {
        printf("index:%d data:%s\n",index,comand_argv[index]);
    }
#else
    if(comand_argc < 2)
    {
        iRet = false;
        printf("errormsg [%s][%d] [%s]\n",__FILE__,__LINE__,__FUNCTION__); 
        goto end;
    }

    messageDeal(msgPtr, comand_argc, comand_argv);
    
#endif

end:
    /*free argv */
    for(index=0;index<comand_argc;index++)
    {   
        if(comand_argv[index] != NULL)
            free(comand_argv[index]);
    }
    
    if(comand_argv != NULL)
        free(comand_argv);

    return iRet;
}

bool MsgQueueManage::shureCommandDo(MessagePtr& msgPtr)
{
    bool iRet = true;
    
    const unsigned char *data = msgPtr->data;
    int iLen = strlen(data);

    if(iLen < 2)
    {
        printf("errormsg [%s][%d] [%s]\n",__FILE__,__LINE__,__FUNCTION__); 
        return false;
    }

    //LOG_PrintInfo("shureCommandDo:data:%s, iLen:%d, size:%d\n",data, iLen, msgPtr->size);

    unsigned char * comandData = NULL;
    comandData = (unsigned char *)malloc(iLen * sizeof(unsigned char *));
    if(comandData == NULL)
    {
        free(comandData);
        printf("errormsg [%s][%d] [%s]\n",__FILE__,__LINE__,__FUNCTION__); 
        return false;
    }

    int iRealLen = iLen - 2;
    int iOffsetTail = 1;

    strncpy(comandData,&data[iOffsetTail],iRealLen);
    comandData[iRealLen] = '\0';
    //LOG_PrintInfo("shureCommandDo:comandData:%s\n",comandData);

    if(!shureCommandPrase(msgPtr, comandData,iRealLen))
    {
        iRet = false;
    }

    //LOG_PrintInfo("dev-type:%d dev-index:%d\n",pstShureCfg->emDevType,pstShureCfg->iDislpayStatus);

    free(comandData);
    return iRet;
}

MsgQueueManage* MsgQueueManage::instance(uint16_t port)
{
    std::lock_guard<std::recursive_mutex> guard(sm_mapMutex);
    
	if(sm_objectMap.find(port) == sm_objectMap.end())
	{
		sm_objectMap[port] = new MsgQueueManage(port);
	}

	return sm_objectMap[port];
}


MsgQueueManage::MsgQueueManage(uint16_t port) 
{   
    m_dealPort = port;

    initProtocolInfo();
}

MsgQueueManage::~MsgQueueManage() 
{   

}

bool MsgQueueManage::initProtocolInfo()
{
    //客户端请求信息
    m_clientReqInfoVec.emplace_back(CMD_KEEP_LIVE);
    m_clientReqInfoVec.emplace_back(CMD_SLAVE_DEV_IP);
    m_clientReqInfoVec.emplace_back(CMD_SHOW_DEVICE_IP);
    m_clientReqInfoVec.emplace_back(CMD_SLAVE_DEV_TRACK_MODE);
    m_clientReqInfoVec.emplace_back(CMD_SLAVE_DEV_POSITION);

    //服务端应答信息
    m_svrRepInfoVec.emplace_back(CMD_VIDEO_SPEAKING_SLAVE_DEVICE);
    m_svrRepInfoVec.emplace_back(CMD_EVENT_RES);
    
    return true;
}

bool MsgQueueManage::startReceiveTherad()
{
    
    
    if(!m_threadFlg)
    {
        m_thread.start([this](Fdt::Thread *thread){this->ThreadProc(thread);});
        m_threadFlg = true;
    }

    return true;
}

bool MsgQueueManage::SaveToCommQueue(MessagePtr& msg)
{
	if(msg.get() != NULL && m_frameaQueue.size() < 1024)
	{
		m_queueMutex.lock();

	    m_frameaQueue.push(msg);

		m_queueMutex.unlock();
	}
	else
	{
	    m_queueMutex.lock();
	    m_frameaQueue.front();//处理队列中消息,移除最早的数据	
    	m_frameaQueue.pop();
    	m_queueMutex.unlock();
	    printf("enter [%s] [%d] size=%d\n",__FILE__,__LINE__, m_frameaQueue.size());
	}
	return true;
}

bool MsgQueueManage::GetCommQueueMsg(MessagePtr& msg)
{
	m_queueMutex.lock();
	if(!m_frameaQueue.empty())
	{	    
    	msg = m_frameaQueue.front();//处理队列中消息		
    	m_frameaQueue.pop();
	
    	//printf("enter [%s] [%d] \n",__FILE__,__LINE__);
    	m_queueMutex.unlock();
    	return true;
	}
	m_queueMutex.unlock();
	return false;
}

void MsgQueueManage::ThreadProc(Fdt::Thread *thread)
{
    printf("enter [%s] [%d] \n",__FILE__,__LINE__);
    thread->setPriority(Fdt::PRIORITY_NORMAL, Fdt::POLICY_RR); 

    MessagePtr msgPtr;
    
    while(thread->running())
    {
        if(!GetCommQueueMsg(msgPtr))
        {
            thread->sleep(100);
            continue;
        }

        //printf("DealThreadProc m_dealPort:%d, Addr=%s, del_buf=%s, Length=%d\n",m_dealPort, (msgPtr->commAddr).c_str(), msgPtr->data, msgPtr->size);

        shureCommandDo(msgPtr);

        thread->sleep(50);
    }
    
    return;
}

bool MsgQueueManage::messageDeal(MessagePtr& msgPtr, int comand_argc, char** comand_argv)
{
    MEDIA_shureConfig_t pstShureCfg;
    
    if(comand_argc < 2
      || comand_argv == NULL)
    {
        printf("errormsg [%s][%d] [%s]\n",__FILE__,__LINE__,__FUNCTION__); 
        return false;
    }

    printf("messageDeal::msg->commAddr=%s,dealData=",msgPtr->commAddr.c_str());
    for(size_t i = 0; i < comand_argc; ++i)
    {
        printf(" %s", comand_argv[i]);
    }
    printf("\n");
    
    string cmdHead = comand_argv[0];
    string cmdKey = comand_argv[1];

    auto itReq = std::find(m_clientReqInfoVec.begin(), m_clientReqInfoVec.end(), cmdKey); 
    auto itRep = std::find(m_svrRepInfoVec.begin(), m_svrRepInfoVec.end(), cmdKey); 

    if(itReq == m_clientReqInfoVec.end() 
      && itRep == m_svrRepInfoVec.end())
    {
        errorf("cmdKey:%s not found\n", cmdKey.c_str());
        return false;
    }
    //printf("messageDeal cmdKey:%s\n", cmdKey.c_str());

    bool slaveAct = false;
    char slaveData[16] = {0};
    size_t length = 0;

    if(2 == comand_argc)
    {
        if(cmdHead == HEARD_REP)
        {
            if(cmdKey == CMD_KEEP_LIVE)
            MediaTcpClient::instance(msgPtr->commAddr)->sendKeepLive();
        }
        if(cmdHead == HEARD_REQ_GET)
        {   
            if(cmdKey == CMD_KEEP_LIVE)
            {
                pstShureCfg.reponseInfo = "< " + HEARD_REP + " " + cmdKey + " >"; 
            }
            else if(cmdKey == CMD_SLAVE_DEV_IP)
            {
                std::set<std::string> devIpSet;
                CurtainActManager::instance()->getCameraInfo(devIpSet);
                std::string devIp;

                for(auto it:devIpSet)
                {
                    devIp = devIp + " [ " + it + " ]";
                }

                devIp = " " + std::to_string(devIpSet.size()) + " " + devIp;
                
                pstShureCfg.reponseInfo = "< " + HEARD_REP + devIp + " >"; 
            }
        }
        
    }
    if(3 == comand_argc)
    {
        const char *param = comand_argv[2];
        
        if(cmdHead == HEARD_REP)
        {
            if(cmdKey == CMD_VIDEO_SPEAKING_SLAVE_DEVICE)
            {
                pstShureCfg.iDislpayStatus = atoi(param);
                
                if(pstShureCfg.iDislpayStatus == 1)
                CurtainActManager::instance()->multiCameraSwitch(msgPtr->commAddr);

                //printf("enter CMD_VIDEO_SPEAKING_SLAVE_DEVICE, param:%s\n", param);
            }
        }
        else if(cmdHead == HEARD_REQ_SET)
        {
            if(cmdKey == CMD_SHOW_DEVICE_IP)
            {
                pstShureCfg.showDevIp = param;

               // printf("enter CMD_SHOW_DEVICE_IP, ip=%s\n", param);

                CurtainActManager::instance()->multiCameraSwitch(pstShureCfg.showDevIp);
                
            }
            else if(cmdKey == CMD_SLAVE_DEV_TRACK_MODE)
            {
                pstShureCfg.slaveDevMode = param;
                
                //printf("enter CMD_SLAVE_DEV_TRACK_MODE param:%s\n",param);

                slaveAct = true;

                length = sizeof(PRESET_SWITCH);
                strncpy(slaveData, PRESET_SWITCH, length); //跟踪模式

                if(pstShureCfg.slaveDevMode == "OFF")
                {
                    slaveData[5] = 0xCB; //手动模式
                }
                
            }
            else if(cmdKey == CMD_SLAVE_DEV_POSITION)
            {
                pstShureCfg.presetPosNum = atoi(param);     

                //printf("enter CMD_SLAVE_DEV_POSITION param:%s\n", param);

                slaveAct = true;
                length = sizeof(PRESET_SWITCH);
                strncpy(slaveData, PRESET_SWITCH, length);
                slaveData[5] = pstShureCfg.presetPosNum; //预置位转动
            }

            pstShureCfg.reponseInfo = "< " + HEARD_REP + " " + cmdKey + " " + param + " >"; 

            if(slaveAct)
            {
                std::set<std::string> devIpSet;
                CurtainActManager::instance()->getCameraInfo(devIpSet);

                for(auto it:devIpSet)
                {
                     MediaUdpClient::instance(it)->sendData(slaveData, length);
                }
            }            
            
        }
    }

    if(!pstShureCfg.reponseInfo.empty())
    {
        MediaUdpServer::instance(UDP_PORT_CONSOLE)->sendData(pstShureCfg.reponseInfo.c_str(), pstShureCfg.reponseInfo.size());
    }
    
    return true;
}


}


